
/**
 * 基本语法 · Kotlin 官方文档 中文版.html https://book.kotlincn.net/text/basic-syntax.html
 */
//fun main() {
//}
fun main1(args: Array<String>) {
    println(args)                   //[Ljava.lang.String;@610455d6
    println(args.toString())        //[Ljava.lang.String;@610455d6
    println(args.contentToString()) //[]

    println(sum(3, 2))                          //5
    println("sum of 3 and 3 is ${sum1(3, 3)}")  //6
    printSum(3, 4)                              //7
}

//2个 Int 参数、返回 Int 的函数
fun sum(a : Int, b : Int) : Int {
    return a + b
}

//函数体可以是表达式。其返回类型可以推断出来
fun sum1(a : Int, b : Int) = a + b

//返回无意义的值的函数, Unit 返回类型可以省略
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}



/**
 * 变量
 */
fun main2() {
    /**
     * 1.定义只读局部变量使用关键字 val 定义。只能为其赋值一次
     */
    val str: String = "Hello World!"
    val a: Int = 5
    val b = 6       //自动推断出 `Int` 类型

    val c: Int      // 如果没有初始值类型不能省略
    c = 3           // 明确赋值
    println("str = $str, a = $a, b = $b, c = $c")

    /**
     * 2.可重新赋值的变量使用 var 关键字。
     */
    var x = 5       // 自动推断出 `Int` 类型
    x += 1
    println("x = $x");
}



/**
 * 创建类与实例
 */
fun main3() {
    val rec = Rectangle(2.0, 3.0);
    println("rec: height = ${rec.perimeter}, width = ${rec.width}, perimeter = ${rec.perimeter}")
}

/**
 * 1.类的属性可以在其声明或主体中列出, 具有类声明中所列参数的默认构造函数会自动可用。
 * 2.默认情况下类都是 final 的；如需让一个类可继承， 请将其标记为 open
 */
public open class Rectangle(var height: Double, val width: Double) : Any() {
    var perimeter = (height + width) * 2        //周长
}


/**
 * 字符串模板
 */
fun main4() {
    var a = 1
    val s1 = "a is $a"      // 模板中的简单名称：

    a = 2
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    println(s2)
}


/**
 * 条件表达式
 */
fun main5() {
    println("max of 3 and 2 is ${maxOf1(3, 2)}")
    println("max of 3 and 5 is ${maxOf2(3, 5)}")
}
fun maxOf1(a : Int, b: Int) : Int {
    if (a > b) {
        return a
    }
    return b
}
//在 Kotlin 中，if 也可以用作表达式。
fun maxOf2(a : Int, b: Int) = if (a > b) a else b


/**
 * for 循环
 */
fun main6() {
    val items = listOf("apple", "banana", "kiwifruit")  //只读 list
    for (item in items) {
        println(item)
    }
    for (index in items.indices) {  //indices （数学中的）指数（index 的复数形式之一）;索引;标志，迹象;食指;（刻度盘上的）指针;指标
        println("item at $index is $items[index]")      //item at 0 is [apple, banana, kiwifruit][index]
        println("item at $index is ${items[index]}")    //item at 0 is apple
        println("item at $index is ${items.get(index)}")//item at 0 is apple
        println()
    }
}


/**
 * while 循环
 */
fun main7() {
    val items = listOf("apple", "banana", "kiwifruit")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index ++
    }
}


/**
 * when 表达式
 */
fun main8() {
    println(describe(1))
    println(describe("Hello"))
    println(describe(1000L))
    println(describe(2))
    println(describe("other"))
}
fun describe(obj: Any) : String =
    when(obj) {
        1           -> "One"
        "Hello"     -> "Greeting"
        is Long     -> "Long"
        !is String  -> "Not a String"
        else        -> "Unknown"
}


/**
 * 使用区间（range）
 */
fun main9() {
    //1.使用 in 操作符来检测某个数字是否在指定区间内。
    val x = 10
    val y = 9
    if (x in 1..y + 1) {
        println("$x fits in range: 1..${y + 1}")        //10 fits in range: 1..10
    }


    //2.检测某个数字是否在指定区间外。
    val list = listOf("a", "b", "c")
    if (-1 !in 0..list.lastIndex) {
        println("-1 is out of range: 0..${list.lastIndex}")     //-1 is out of range: 0..2
    }
    if (list.size !in list.indices) {
        //       list size(3) is out of valid list indices(0..2) range, too
        println("list size(${list.size}) is out of valid list indices(${list.indices}) range, too")
    }


    //3.区间迭代。
    for (x in 1..5) {
        print("$x ")    //1 2 3 4 5
    }
    println()


    //4.数列迭代。
    for (x in 1..10 step 2) {   //step: 每次 ± 2
        print("$x ")            //1 3 5 7 9
    }
    println()
    for (x in 9 downTo 1 step 3) {
        print("$x ")    //9 6 3
    }
}


/**
 * 集合
 */
fun main10() {
    //1.对集合进行迭代。
    val items = listOf("apple", "banana", "kiwifruit")          //没有 add() 方法
    val items1 = mutableListOf("apple", "banana", "kiwifruit")  //有 add() 方法
    for (item in items) {
        println(item)
    }

    //2.使用 in 操作符来判断集合内是否包含某实例。
    when {
        "orange" in items -> println("juicy")
        "apple"  in items -> println("apple is fine too")
    }

    //3.使用 lambda 表达式来过滤（filter）与映射（map）集合：
    items1.add("avocado")       //鳄梨, 牛油果
    items1.filter { it.startsWith("a") }
        .sortedBy { it }
        .map { it.toUpperCase() }
        .forEach { println(it) }
}


/**
 * 空值与空检测
 */
fun main11() {
    //当可能用 null 值时，必须将引用显式标记为可空。可空类型名称以问号（?）结尾。
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}
fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // 直接使用 `x * y` 会导致编译错误，因为它们可能为 null
    if (x != null && y != null) {
        // 在空检测后，x 与 y 会自动转换为非空值（non-nullable）
        println("$x * $y = ${x * y}")
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }
}


/**
 * 类型检测与自动类型转换
 */
fun main12() {
    //is 操作符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出为某类型，那么检测后的分支中可以直接当作该类型使用，无需显式转换：
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}
fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        return obj.length       // `obj` 在该条件分支内自动转换成 `String`
    }
    return null                 // 在离开类型检测分支后，`obj` 仍然是 `Any` 类型
}










